package com.gs.process.core.utils;

import com.gs.process.core.ApprovalApi;
import com.gs.process.core.annotation.ProcessBegin;
import com.gs.process.core.annotation.ProcessEntry;
import com.gs.process.model.Approval;
import com.gs.process.model.dto.Constant;
import com.shallowUniverse.model.Result;
import com.shallowUniverse.utils.AssertUtil;
import com.shallowUniverse.utils.BeanUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.util.ObjectUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @author: Shuai Guo
 * @description:
 * @date: 2021/9/28
 * @version: 1.0
 */
public class AspectUtil {

    /**
     * description: 开启流程 <br/>
     * author: gs   <br/>
     * date: 2021/1/17 <br/>
     * params: [] <br/>
     * return: void
     */
    public static Object beginProcess(ApprovalApi approvalApi, ProceedingJoinPoint joinPoint, ProcessBegin processBegin) {
        //定义返回值
        Object returnValue = null;
        try {
            //调用方法保存目标表信息
            returnValue = joinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        //调用方法拿到主键和流程号
        Map<Constant, Object> params = analysisProcessEntry(joinPoint);
        //判断是否为空，为空证明没有增加ProcessEntry注解或者流程号为空
        if (ObjectUtils.isEmpty(params)) {
            return returnValue;
        }
        //保存申请单
        Approval approval = new Approval();
        //设置目标表id
        approval.setTargetId(params.get(Constant.PRIMARY_KEY).toString());
        //设置目标表名
        approval.setTarget(processBegin.value());
        //设置流程id
        approval.setProcessId(Long.parseLong(params.get(Constant.PROCESS_FIELD).toString()));
        //设置目标表主键字段名
        //判断是否是驼峰
        boolean underScoreCamelCase = (boolean) params.get(Constant.UNDERSCORE_TO_CAMEL_CASE);
        if (underScoreCamelCase) {
            approval.setPrimaryKey(params.get(Constant.PRIMARY_KEY_FIELD).toString().replaceAll("[A-Z]", "_$0").toLowerCase());
        } else {
            approval.setPrimaryKey(params.get(Constant.PRIMARY_KEY_FIELD).toString());
        }
        Result<Long> result = approvalApi.save(approval);
        //返回返回值
        return returnValue;
    }

    /**
     * description: 获取主键值 <br/>
     * author: gs   <br/>
     * date: 2020/12/18 <br/>
     * params: [joinPoint] <br/>
     * return: java.lang.Object
     */
    private static Map<Constant, Object> analysisProcessEntry(ProceedingJoinPoint joinPoint) {
        //判断是否返回了result（没有返回就从ProcessEntry中尝试获取）
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        //拿到参数
        Map<Constant, Object> params = parseProcessEntry(method, joinPoint.getArgs());
        //判断参数是否为空
        if (ObjectUtils.isEmpty(params)) {
            return null;
        }
        //判断流程号是否为空
        if (ObjectUtils.isEmpty(params.get(Constant.PROCESS_FIELD))) {
            return null;
        }
        //判断主键是否为空
        AssertUtil.service().notNull(params.get(Constant.PRIMARY_KEY), "主键不能为空");
        return params;
    }

    /**
     * description: 解析ProcessEntry拿到主键值 <br/>
     * author: Shuai Guo   <br/>
     * date: 2021/7/29 <br/>
     * params: [method, args] <br/>
     * return: java.util.Map<java.lang.String,java.lang.Object> <br/>
     * version: 1.0
     */
    public static Map<Constant, Object> parseProcessEntry(Method method, Object[] args) {
        ProcessEntry processEntry = null;
        int index = -1;
        //获取方法参数注解
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        for (int i = 0; i < parameterAnnotations.length; i++) {
            for (int j = 0; j < parameterAnnotations[i].length; j++) {
                //判断是否是ProcessEntry注解
                if (parameterAnnotations[i][j].annotationType() == ProcessEntry.class) {
                    processEntry = (ProcessEntry) parameterAnnotations[i][j];
                    index = i;
                }
            }
        }
        //判断是否取到了注解
        if (ObjectUtils.isEmpty(processEntry)) {
            return null;
        }
        //拿到注解对应的参数
        Object entry = args[index];
        //拿到主键字段名
        String primaryKey = processEntry.primaryKey();
        //拿到流程字段名
        String processField = processEntry.processField();
        //设置参数值
        Map<Constant, Object> params = new HashMap<>(2);
        params.put(Constant.PRIMARY_KEY, BeanUtil.getProperty(entry, primaryKey));
        params.put(Constant.PROCESS_FIELD, BeanUtil.getProperty(entry, processField));
        params.put(Constant.PRIMARY_KEY_FIELD, primaryKey);
        params.put(Constant.UNDERSCORE_TO_CAMEL_CASE, processEntry.underscoreToCamelCase());
        //返回参数
        return params;
    }
}
